﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TimeTracker_Entities;
using System.Data.Objects;

namespace TimeTracker_BL.Repositories
{
    public class TimeTrackerRepository : ITimeTrackerRepository
    {
        /// <summary>
        /// Gets all time entries.
        /// </summary>
        /// <returns>A list of <see cref="TimeEntry"/> objects</returns>
        public IList<TimeEntry> GetAllTimeEntries()
        {
            List<TimeEntry> timeEntryList = new List<TimeEntry>();

            using (var ctx = new TimeTrackerEntitiesContainer())
            {
                // Get an ordered list of Billing Terms
                var entries = from e in ctx.TimeEntries.Include("Project").Include("Project.Client")
                              orderby e.DateWorked descending
                              select e;

                timeEntryList = entries.ToList<TimeEntry>();
            }

            return timeEntryList;
        }


        /// <summary>
        /// Gets all time entries between the given dates.
        /// </summary>
        /// <param name="startDate">The start date.</param>
        /// <param name="endDate">The end date.</param>
        /// <returns>A list of <see cref="GetTimesheetReportDataByWeek_Result"/> objects</returns>
        public IList<GetTimesheetReportDataByWeek_Result> GetAllTimeEntriesBetween(DateTime startDate, DateTime endDate)
        {
            // Instantiate the result list
            List<GetTimesheetReportDataByWeek_Result> timeEntryList = new List<GetTimesheetReportDataByWeek_Result>();

            using (var ctx = new TimeTrackerEntitiesContainer())
            {
                // Get an ordered list of Billing Terms
                var data = ctx.GetTimesheetReportDataByWeek(startDate, endDate);

                // Convert the data to an List
                timeEntryList = data.ToList<GetTimesheetReportDataByWeek_Result>();
            }

            return timeEntryList;
        }

        /// <summary>
        /// Adds the entry.
        /// </summary>
        /// <param name="entryToAdd">The entry to add.</param>
        /// <param name="userId">The user id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult AddEntry(TimeEntry entryToAdd, string userId)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Capture the create date/time and user
                    entryToAdd.CreatedAt = DateTime.Now;
                    entryToAdd.CreatedBy = userId;

                    // Add the object
                    ctx.TimeEntries.AddObject(entryToAdd);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }
        /// <summary>
        /// Updates the entry.
        /// </summary>
        /// <param name="updatedEntry">The updated entry.</param>
        /// <param name="userId">The user id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult UpdateEntry(TimeEntry updatedEntry)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Update the object
                    var entry = ctx.TimeEntries.Single(t => t.TimeEntryId == updatedEntry.TimeEntryId);
                    updatedEntry.CreatedAt = entry.CreatedAt;
                    updatedEntry.CreatedBy = entry.CreatedBy;
                    ctx.ApplyCurrentValues<TimeEntry>("TimeEntries", updatedEntry);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }
        /// <summary>
        /// Deletes the entry.
        /// </summary>
        /// <param name="timeEntryId">The time entry id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult DeleteEntry(int timeEntryId)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Delete the object
                    var entry = ctx.TimeEntries.First(e => e.TimeEntryId == timeEntryId);
                    ctx.TimeEntries.DeleteObject(entry);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }

        /// <summary>
        /// Gets the clients.
        /// </summary>
        /// <returns>a list of <see cref="Client"/> objects.</returns>
        public IList<Client> GetClients()
        {
            List<Client> clientList = new List<Client>();

            using (var ctx = new TimeTrackerEntitiesContainer())
            {
                // Get an ordered list of Billing Terms
                var clients = from c in ctx.Clients.Include("BillingTerm")
                            orderby c.ClientName
                            select c;

                clientList = clients.ToList<Client>();
            }

            return clientList;
        }

        /// <summary>
        /// Adds the client.
        /// </summary>
        /// <param name="clientToAdd">The client to add.</param>
        /// <param name="userId">The user id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult AddClient(Client clientToAdd)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Add the object
                    ctx.Clients.AddObject(clientToAdd);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }
        /// <summary>
        /// Updates the client.
        /// </summary>
        /// <param name="updatedClient">The updated client.</param>
        /// <param name="userId">The user id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult UpdateClient(Client updatedClient)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Update the object
                    var currentClient = ctx.Clients.Single(c => c.ClientId == updatedClient.ClientId);
                    ctx.ApplyCurrentValues<Client>("Clients", updatedClient);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }
        /// <summary>
        /// Deletes the client.
        /// </summary>
        /// <param name="clientId">The client id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult DeleteClient(int clientId)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Delete the object
                    var client = ctx.Clients.First(c => c.ClientId == clientId);
                    ctx.Clients.DeleteObject(client);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }

        /// <summary>
        /// Gets the projects.
        /// </summary>
        /// <returns>a list of <see cref="Project"/> objects.</returns>
        public IList<Project> GetProjects()
        {
            var projectList = new List<Project>();

            using (var ctx = new TimeTrackerEntitiesContainer())
            {
                // Get an ordered list of Billing Terms
                var projects = from p in ctx.Projects.Include("Client")
                              orderby p.ProjectName
                              select p;

                projectList = projects.ToList<Project>();
            }

            return projectList;
        }

        /// <summary>
        /// Adds the Project.
        /// </summary>
        /// <param name="projectToAdd">The Project to add.</param>
        /// <param name="userId">The user id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult AddProject(Project projectToAdd)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Add the object
                    ctx.Projects.AddObject(projectToAdd);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }
        /// <summary>
        /// Updates the Project.
        /// </summary>
        /// <param name="updatedProject">The updated Project.</param>
        /// <param name="userId">The user id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult UpdateProject(Project updatedProject)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Update the object
                    var currentProject = ctx.Projects.Single(c => c.ProjectId == updatedProject.ProjectId);
                    ctx.ApplyCurrentValues<Project>("Projects", updatedProject);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }
        /// <summary>
        /// Deletes the Project.
        /// </summary>
        /// <param name="ProjectId">The Project id.</param>
        /// <returns>
        /// An <see cref="IOpResult"/> object containing data including whether or 
        /// not the operation was successful and any error messages.
        /// </returns>
        public IOpResult DeleteProject(int projectId)
        {
            var result = new OpResult();

            try
            {
                using (var ctx = new TimeTrackerEntitiesContainer())
                {
                    // Delete the object
                    var Project = ctx.Projects.First(c => c.ProjectId == projectId);
                    ctx.Projects.DeleteObject(Project);
                    ctx.SaveChanges();

                    // Return success
                    result.IsSuccessful = true;
                    return result;
                }
            }
            catch (Exception ex)
            {
                // Return failure
                result.IsSuccessful = false;
                result.ErrorMessage = ex.Message;
                return result;
            }
        }
    }
}
